package com.spring.core.context;


import com.spring.core.factory.BeanFactory;
import com.spring.core.mapping.HandlerMapping;
import com.spring.core.wired.FieldAutowired;
import com.spring.core.wired.FieldValueWired;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 应用程序上下文抽像
 *
 * @author Zee
 * @version 1.0
 * @date 2021/11/1
 */

public abstract class AbstractApplicationContext implements ApplicationContext {

    /**
     * 配置文件
     */
    private Properties properties;
    /**
     * 扫描的类路径
     */
    private List<String> classNames;
    /**
     * 扫描包路径
     */
    private String scanPackage;
    /**
     * IOC容器
     */
    private Map<String, Object> ioc;
    /**
     * handlerMapping容器
     */
    private Map<String, Method> mapping;

    public AbstractApplicationContext(Class<?> clazz) {
        this.classNames = new ArrayList<>();
        this.mapping = new HashMap<>(16);
        this.ioc = new HashMap<>(16);
        this.properties = new Properties();
        this.scanPackage = clazz.getPackage().getName();
    }


    /**
     * 获取Bean对像
     *
     * @param key bean对像key
     * @return
     */
    @Override
    public Object getBean(String key) {
        return this.ioc.get(key);
    }

    @Override
    public <T> Map<String, T> getBeanOfType(Class<T> clazz) {
        Map<String, T> result = new LinkedHashMap<>();
        if (clazz.isInterface()) {
            this.ioc.forEach((key, v) -> {
                Class<?>[] interfaces = v.getClass().getInterfaces();
                for (Class<?> anInterface :interfaces) {
                    if (anInterface.getTypeName().equals(clazz.getTypeName())) {
                        if (result.containsValue(v)) {
                            continue;
                        }
                        result.put(key, (T) v);
                        break;
                    }
                }
            });
        }
        return result;
    }

    @Override
    public void putBean(String key, Object bean) {
        this.ioc.put(key, bean);
    }

    public List<String> getClassNames() {
        return classNames;
    }

    public String getScanPackage() {
        return scanPackage;
    }

    public Map<String, Object> getIoc() {
        return ioc;
    }

    /**
     * 获取mapping容器
     *
     * @return
     */
    public Map<String, Method> getMapping() {
        return mapping;
    }

    /**
     * 获取配置信息
     *
     * @return
     */
    public Properties getProperties() {
        return properties;
    }


    @Override
    public void init() {
        //扫描文件
        scan();
        //Bean初始化
        beanInit();
        //依赖注入
        wired();
        //初始化handlerMapping
        initHandlerMapping();
    }

    /**
     * 依赖注入
     */
    private void wired() {
        BeanFactory.getBean(FieldAutowired.class).doWired(this);
        BeanFactory.getBean(FieldValueWired.class).doWired(this);
    }

    /**
     * 初始化handlerMapping
     */
    private void initHandlerMapping() {
        BeanFactory.getBean(HandlerMapping.class).initHandlerMapping(this);
    }

    /**
     * 扫描文件
     */
    protected abstract void scan();

    /**
     * 初始化Bean对像
     */
    protected abstract void beanInit();


}
